<?php
/**
 * 生成文本缓存类
 *
 * @copyright
 */

class Cache {

    private $db;
    private static $instance = null;

    private $options_cache;
    private $options_category;

    private function __construct() {
        $this->db = Database::getInstance();
    }

    /**
     * 静态方法，返回数据库连接实例
     *
     * @return Cache
     */
    public static function getInstance() {
        if (self::$instance == null) {
            self::$instance = new Cache();
        }
        return self::$instance;
    }
    /**
     * 更新缓存
     * 
     * @param array/string $cacheMethodName 需要更新的缓存，更新多个采用数组方式：array('options', 'user'),单个采用字符串方式：'options',全部则留空
     * @return unknown_type
     */
    function updateCache($cacheMethodName = null) {
        // 更新单个缓存
        if (is_string($cacheMethodName)) {
            if (method_exists($this, 'mc_' . $cacheMethodName)) {
                call_user_func(array($this, 'mc_' . $cacheMethodName));
            }
            return;
        }
        // 更新多个缓存
        if (is_array($cacheMethodName)) {
            foreach ($cacheMethodName as $name) {
                if (method_exists($this, 'mc_' . $name)) {
                    call_user_func(array($this, 'mc_' . $name));
                }
            }
            return;
        }
        // 更新全部缓存
        if ($cacheMethodName == null) {
            // 自动运行本类所有更新缓存的方法(此类方法的名称必须由mc_开头)
            $cacheMethodNames = get_class_methods($this);
            foreach ($cacheMethodNames as $method) {
                if (preg_match('/^mc_/', $method)) {
                    call_user_func(array($this, $method));
                }
            }
        }
    }
    /**
     * 站点配置缓存
     * 注意更新缓存的方法必须为mc开头
     */
    private function mc_options() {
        $options_cache = array();
        $res = $this->db->query("SELECT * FROM " . DB_PREFIX . "options");
        while ($row = $this->db->fetch_array($res)) {
            if (in_array($row['option_name'], array('site_title', 'site_name', 'site_description', 'site_url'))) {
                $row['option_value'] = htmlspecialchars($row['option_value']);
            }
            $options_cache[$row['option_name']] = $row['option_value'];
        }
        $cacheData = serialize($options_cache);
        $this->cacheWrite($cacheData, 'options');
    }

    private function mc_category() {
        $category_cache = array();
        $product_category = array();
        $article_category = array();
        $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "category ORDER BY pid ASC,taxis ASC");
        while ($row = $this->db->fetch_array($query)){
            if($row['model']=='product'){
                $data = $this->db->once_fetch_array("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "product WHERE catid=" . $row['catid']);
                $postNum = $data['total'];
                $catData = array(
                    'postnum' => $postNum,
                    'catname' => htmlspecialchars($row['catname']),
                    'description' => htmlspecialchars($row['description']),
                    'alias' =>$row['alias'],
                    'catid' => intval($row['catid']),
                    'taxis' => intval($row['taxis']),
                    'pid' => intval($row['pid']),
                    'template' => htmlspecialchars($row['template']),
                    'caturl' => Url::productCategory($row['catid']),
                    'model' => htmlspecialchars($row['model']),
                    );
                if ($catData['pid'] == 0) {
                    $catData['children'] = array();
                } elseif (isset($product_category[$row['pid']])) {
                    $product_category[$row['pid']]['children'][] = $row['catid'];
                }
                $product_category[$row['catid']] = $catData;
                $category_cache['product'] = $product_category;
            }else{
                $data = $this->db->once_fetch_array("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "article WHERE catid=" . $row['catid']);
                $postNum = $data['total'];
                $catData = array(
                    'postnum' => $postNum,
                    'catname' => htmlspecialchars($row['catname']),
                    'description' => htmlspecialchars($row['description']),
                    'alias' =>$row['alias'],
                    'catid' => intval($row['catid']),
                    'taxis' => intval($row['taxis']),
                    'pid' => intval($row['pid']),
                    'template' => htmlspecialchars($row['template']),
                    'caturl' => Url::articleCategory($row['catid']),
                    'model' => htmlspecialchars($row['model']),
                    );
                if ($catData['pid'] == 0) {
                    $catData['children'] = array();
                } elseif (isset($article_category[$row['pid']])) {
                    $article_category[$row['pid']]['children'][] = $row['catid'];
                }
                $article_category[$row['catid']] = $catData;
                $category_cache['article'] = $article_category;
            }
        }
        $cacheData = serialize($category_cache);
        $this->cacheWrite($cacheData, 'category');
    }


    /**
     * 写入缓存
     */
    function cacheWrite ($cacheData, $cacheName) {
        $cachefile = APP_ROOT . '/data/cache/' . $cacheName . '.php';
        $cacheData = "<?php exit;//" . $cacheData;
        @ $fp = fopen($cachefile, 'wb') OR idooMsg('读取缓存失败。如果您使用的是Unix/Linux主机，请修改缓存目录 (data/cache) 下所有文件的权限为777。如果您使用的是Windows主机，请联系管理员，将该目录下所有文件设为可写');
        @ $fw = fwrite($fp, $cacheData) OR idooMsg('写入缓存失败，缓存目录 (data/cache) 不可写');
        $this->{$cacheName.'_cache'} = null;
        fclose($fp);
    }

    /**
     * 读取缓存文件
     */
    function readCache($cacheName) {
        if ($this->{$cacheName.'_cache'} != null) {
            return $this->{$cacheName.'_cache'};
        } else {
            $cachefile = APP_ROOT . '/data/cache/' . $cacheName . '.php';
            // 如果缓存文件不存在则自动生成缓存文件
            if (!is_file($cachefile) || filesize($cachefile) <= 0) {
                if (method_exists($this, 'mc_' . $cacheName)) {
                    call_user_func(array($this, 'mc_' . $cacheName));
                }
            }
            if ($fp = fopen($cachefile, 'r')) {
                $data = fread($fp, filesize($cachefile));
                fclose($fp);
                clearstatcache();
                $this->{$cacheName.'_cache'} = unserialize(str_replace("<?php exit;//", '', $data));
                return $this->{$cacheName.'_cache'};
            }
        }
    }
}
